package com.ruoyi.common.utils.oss;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.BucketInfo;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.aliyun.oss.model.PutObjectResult;
import com.ruoyi.common.config.AliYunConfig;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.utils.oss.model.AliYunOssPostParamResult;
import com.ruoyi.common.utils.oss.model.AliYunUploadResult;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * 阿里云OSS上传工具
 *
 * @author HHKJ-SERVER-ZJ
 */
public class AliYunOSSUtils
{

    /**
     * 获取阿里云OSS客户端对象
     *
     * @return ossClient
     */
    public static OSSClient getOSSClient()
    {
        return new OSSClient(AliYunConfig.getOSSEndpoint(), AliYunConfig.getAccessKeyId(), AliYunConfig.getAccessKeySecret());
    }

    /**
     * 生成阿里云OSS Post请求所需要的参数信息
     *
     * @return 阿里云OSS Post请求所需要的参数信息
     */
    public static AliYunOssPostParamResult generateOssPostParam()
    {
        AliYunOssPostParamResult result = new AliYunOssPostParamResult();
        // 1、获取客户
        OSSClient ossClient = getOSSClient();

        // 2、Conditions 条件参数
        // 2.1、设置有效时间 为一分钟内有效
        Date currentTime = new Date();
        DateTime expirationTime = DateUtil.offsetSecond(currentTime, 300);
        PolicyConditions policyConditions = new PolicyConditions();
        policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, AliYunConfig.getProjectRootFolderName());
        String postPolicy = ossClient.generatePostPolicy(expirationTime, policyConditions);
        // 3、数据处理
        byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
        String encodedPolicy = BinaryUtil.toBase64String(binaryData);
        String postSignature = ossClient.calculatePostSignature(postPolicy);

        return result.setAccessId(AliYunConfig.getAccessKeyId())
                .setPolicy(encodedPolicy)
                .setSignature(postSignature)
                .setDir(AliYunConfig.getProjectRootFolderName())
                .setHost(AliYunConfig.getUrlPrefix())
                .setExpireTime(expirationTime)
                .setExpire(DateUtil.second(currentTime));
    }

    /**
     * 阿里云接收前端文件上传方法
     *
     * @param file   MultipartFile文件
     * @param putKey 上传文件key  （文件夹 + ”/“ + 文件名）
     * @return 上传结果
     */
    public static AliYunUploadResult uploadMultipartFileToOSS(MultipartFile file, String putKey)
    {
        OSSClient ossClient = getOSSClient();
        PutObjectResult putResult;
        AliYunUploadResult result = new AliYunUploadResult();
        try {
            InputStream inputStream = file.getInputStream();
            // 创建PutObject请求。
            putResult = ossClient.putObject(AliYunConfig.getOSSBucketName(), putKey, inputStream);
            result.setPutResult(putResult)
                    .setResultFlag(true);
        } catch (OSSException oe) {
            /*System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());*/
            // TODO: 2022/3/1 记录 OSSException 异常信息，先完成功能，后续开发继续
            result.setResultFlag(false)
                    .setExceptionInfo("上传服务器失败, 请联系管理员");
        } catch (ClientException ce) {
            /*System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());*/
            result.setResultFlag(false)
                    .setExceptionInfo("客户端上传失败, 请联系管理员");
        } catch (IOException e) {
            result.setResultFlag(false)
                    .setExceptionInfo("文件上传失败, 请联系管理员");
        } finally {
            ossClient.shutdown();
        }
        return result;
    }

    public static AliYunUploadResult uploadMultipartFileToOSS(InputStream inputStream, String putKey)
    {
        OSSClient ossClient = getOSSClient();
        PutObjectResult putResult;
        AliYunUploadResult result = new AliYunUploadResult();
        try {
            // 创建PutObject请求。
            putResult = ossClient.putObject(AliYunConfig.getOSSBucketName(), putKey, inputStream);
            result.setPutResult(putResult)
                    .setResultFlag(true);
        } catch (OSSException oe) {
            /*System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());*/
            // TODO: 2022/3/1 记录 OSSException 异常信息，先完成功能，后续开发继续
            result.setResultFlag(false)
                    .setExceptionInfo("上传服务器失败, 请联系管理员");
        } catch (ClientException ce) {
            /*System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());*/
            result.setResultFlag(false)
                    .setExceptionInfo("客户端上传失败, 请联系管理员");
        } catch (Exception e) {
            result.setResultFlag(false)
                    .setExceptionInfo("文件上传失败, 请联系管理员");
        } finally {
            ossClient.shutdown();
        }
        return result;
    }
}
